﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;

namespace Pasta.Medio.Configuration
{
	/// <summary>
	/// Local configuration stored in 
	/// </summary>
	/// <example>
	/// Retrieve a configuration
	///		Config config = new Config( "Pasta", "Medio" );
	/// Set a top level key
	///		config["Skin"] = "Blue";
	/// Retrieve a configuration section
	///		ConfigSection section = config.GetSection( "Printers" );
	///	Manipulate keys in the section
	///		section["DefaultPrinter"] = "Canon";
	/// </example>
	public class Config
	{
		public System.Configuration.Configuration _cfg { get; set; }

		public string Company { get; set; }
		public string Product { get; set; }

		public Config(string company, string product)
		{
			Company = company;
			Product = product;
			string configDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
			string companyDir = Path.Combine(configDir, company);
			if (!Directory.Exists(companyDir))
			{
				Directory.CreateDirectory(companyDir);
			}
			string productDir = Path.Combine(companyDir,product);
			if (!Directory.Exists(productDir))
			{
				Directory.CreateDirectory(productDir);
			}
			// set the |DataDirectory|
			AppDomain.CurrentDomain.SetData("DataDirectory", productDir);
			ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
			product = Path.ChangeExtension(product, ".config");
			configFileMap.ExeConfigFilename = Path.Combine(productDir, product);
			_cfg = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
			// _cfg.HasFile indicates whether the Medio.config file exists
		}

		public bool HasFile { get { return _cfg.HasFile; } }
		public string FilePath { get { return _cfg.FilePath; } }

		/// <summary>
		/// A product level configuration setting
		/// </summary>
		/// <param name="key"></param>
		/// <returns></returns>
		public string this[string key]
		{
			get
			{
				string value = string.Empty;
				ConfigSection ls = GetSection(Product);
				if (ls != null)
				{
					value = ls[key];
				}
				return value;
			}
			set
			{
				ConfigSection ls = GetSection(Product);
				if (ls != null)
				{
					ls[key] = value;
				}
			}
		}

		/// <summary>
		/// Retreive a named section
		/// </summary>
		/// <param name="sectionName"></param>
		/// <returns></returns>
		public ConfigSection GetSection(string sectionName)
		{
			return new ConfigSection(this, sectionName);
		}

		public AppSettingsSection GetAppSection(string sectionName)
		{
			AppSettingsSection section;
			sectionName = sectionName.Replace(' ', '_');
			if (_cfg.Sections[sectionName] == null)
			{
				section = new AppSettingsSection();
				//section.SectionInformation.AllowExeDefinition = ConfigurationAllowExeDefinition.MachineToLocalUser;
				_cfg.Sections.Add(sectionName, section);
			}
			else
			{
				section = (AppSettingsSection)_cfg.Sections[sectionName];
			}
			_cfg.Save(ConfigurationSaveMode.Minimal);
			return section;
		}

		public Dictionary<string, string> ListKeyValuePairs(string section)
		{
			AppSettingsSection settings = GetAppSection(section);
			Dictionary<string, string> kv = new Dictionary<string, string>();
			foreach (string key in settings.Settings.AllKeys)
			{
				kv[key] = settings.Settings[key].Value;
			}
			return kv;
		}

		public bool Save()
		{
			try
			{
				_cfg.Save(ConfigurationSaveMode.Minimal);
				return true;
			}
			catch
			{
				return false;
			}
		}
	}

	public class ConfigSection
	{
		private Config _config;
		private AppSettingsSection _section;

		/// <summary>
		/// Constructor for a section in the configuration with the name passed
		/// </summary>
		/// <param name="config">Configutation</param>
		/// <param name="sectionName">Section name</param>
		public ConfigSection(Config config, string sectionName)
		{
			_config = config;
			_section = config.GetAppSection(sectionName);
		}

		/// <summary>
		/// Indexer for a key in the section
		/// </summary>
		/// <param name="key">key</param>
		/// <returns>value</returns>
		public string this[string key]
		{
			get
			{
				string value = string.Empty;
				if (_section.Settings.AllKeys.Contains(key))
				{
					value = _section.Settings[key].Value;
				}
				return value;
			}
			set
			{
				if (_section.Settings.AllKeys.Contains(key))
					_section.Settings[key].Value = value;
				else
					_section.Settings.Add(key, value);
				_config.Save();
			}
		}
	}

}
